import argparse, os, inspect, datetime, platform  # noqa: E401
import random
from subprocess import run

# 定义全局函数字典(勿删)
functions = {}
# 定义是否使用预设菜单布局, True为使用, False为不使用
USE_PRESET_MENU_IT = True
# 定义缓存文件路径
kylin_file_path = "/tmp/kylin_install_file/"


# 装饰器定义, 接受两个参数：key 和 description
def switch_func(key, description, hidden=False):
    """
    装饰器函数, 用于将函数注册到全局的函数映射表中

    Args:
        key (str): 菜单项的键名
        description (str): 菜单项的描述信息
        hidden (bool, optional): 是否隐藏该菜单项, 默认为False

    Returns:
        function: 装饰器函数, 用于将函数注册到全局的函数映射表中
    """

    def decorator(func):
        func.menu_key = key
        func.menu_description = description
        if hidden:
            func.hidden = True
        else:
            func.hidden = False
        functions[key] = func
        return func

    return decorator


# 公有执行函数封装
class Kylin_Tools_Common:
    # 执行封装
    def cmd(
        self,
        command: str,
    ):
        """
        执行语句命令
        :param command: 需要执行的命令
        :return: 返回执行结果
        """
        back = run(command, shell=True, capture_output=True, text=True)
        if back.returncode == 0:
            return back.stdout

    def soft_down_file(
        self,
        file_urls,
        file_path,
    ):
        """
        下载软件安装文件并安装
        :param file_urls: 需要下载的文件URL
        :param file_path: 下载文件存放路径
        :return: 返回是否安装成功, True为成功, False为失败
        """
        # 本地如果没有下载文件夹就新建
        if not os.path.exists(file_path):
            os.system("mkdir -p {}".format(file_path))
        for down_name, down_url in file_urls.items():
            # 查看本地有没有缓存文件, 如果有就安装, 没有就下载安装
            file_name = os.path.basename(down_url)
            if os.path.exists(os.path.join(file_path, file_name)):
                # 本地有缓存, 使用缓存安装
                print("本地有缓存, 使用缓存安装:{}".format(down_name))
            else:
                # 正在下载并安装
                print("正在下载并安装:{}".format(down_name))
                os.system("sudo wget -P {} {} -q --show-progress".format(file_path, down_url))

            try:
                # 正在安装
                print("正在安装{}...".format(down_name))
                self.cmd("sudo dpkg -i {}/{}".format(file_path, file_name))
            except Exception:
                # 安装失败
                print("安装{}失败!!!".format(down_name))
                return False
            else:
                # 安装完成
                print("安装{}完成!!!".format(down_name))
                return True


# 文本类封装
class Kylin_Script_Print:
    def __init__(self) -> None:
        self.logo = inspect.cleandoc(
            r"""
             ____  ____        __   __                ________  ____      ____ 
            |_   ||   _|      [  | [  |              |_   __  ||_  _|    |_  _|
              | |__| |  .---.  | |  | |  .--.          | |_ \_|  \ \  /\  / /  
              |  __  | / /__\\ | |  | |/ .'`\ \        |  _|      \ \/  \/ /   
             _| |  | |_| \__., | |  | || \__. |  _    _| |_        \  /\  /    
            |____||____|'.__.'[___][___]'.__.'  )_/  |_____|        \/  \/     

            ---欢迎使用FW工具箱, 让我们一起来当个废物吧(手动划掉)---
        """
        )

        # 当前运行环境
        self.script_env = inspect.cleandoc(
            f"""
            ---当前系统时间: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
            ---当前操作系统: {kylin_tools_common.cmd('cat /etc/os-release | grep ^ID | sed "s/ID=//" | sed -n 1p').strip() if platform.system() == "Linux" else "Windows"}
            ---当前系统架构: {platform.machine()}
            ---当前工作目录: {os.getcwd()}
            ---当前用户名: {os.getlogin()}
        """
        )

        # 预设菜单
        self.script_much = inspect.cleandoc(
            r"""
            0 退出脚本          0.0 显示菜单
            ————————————软件相关————————————
            安装类：
                1.1 常用安装(粤政易, WPS, 数科, BJCA, 360压缩)
                1.1.1 粤政易    1.1.2 WPS   1.1.3 BJCA证书   1.1.4 360压缩(修复解压乱码)
                1.1.5 数科阅读器    1.1.6 微信(Win版)
            配置类：
                1.2.1 安装WPS证书   1.2.2 浏览器配置(360书签)
            卸载类：
                1.3.1 WPS卸载并清理残存文件
            修复类：
                2.1 杀粤政易(解决无法正常收发消息)  2.2 腾讯会议修复插件(不含本体)
            ————————————系统相关————————————
            3.0 查看系统信息
            3.1 常用公文字体安装    3.2 升级麒麟商店
            3.3 系统更新源及更新软件
            3.4 增加虚拟内存
            ———————————打印机相关————————————
            4.0 安装deepin驱动依赖包
            ————————————————————————————————
            脚本更新时间: 2024.2.1
            如有问题请联系开发者: Warren
        """
        )

        # 预设菜单(内部功能)
        self.script_much_it = inspect.cleandoc(
            """
            ————————————内部功能（慎用）————————————
            4.1 安装打印机驱动(兄弟和华为)
            7.0 初始化安装（字体和软件、证书、密码策略）-未完
            7.1 Apt软件源设置
            Audit_Log:
                7.2.1 查看Audit_log
                7.2.2 破解Audit_log(默认WPS{随机1200-3000}, 开机次数{随机至少280})
            7.3 设置密码相关策略-未完
            7.4 去除开机界面后两项-未完
            7.5 设置FTP扫描, 账号为FTP-未完
            7.6 UOS进入开发者模式, 开启root权限
        """
        )
        self.script_much_all = self.logo + "\n" + self.script_env + "\n" + self.script_much

    # 显示菜单函数, 根据show_hidden参数决定是否显示隐藏功能
    def show_menu(self, show_hidden: bool = False):
        """
        显示菜单函数, 根据show_hidden参数决定是否显示隐藏功能
        :param show_hidden: 是否显示隐藏功能, Ture为显示, False为不显示
        :return: 无返回值
        """
        if USE_PRESET_MENU_IT:
            if show_hidden:
                print(self.script_much_all + "\n" + self.script_much_it)
            else:
                print(self.script_much_all)
        else:
            print(self.logo)
            menu_items = [
                f"{func.menu_key} {func.menu_description}"
                for func in functions.values()
                # show_hidden为True时显示所有菜单项, 否则只显示非隐藏项
                # func.hidden为False时只显示非隐藏项
                if show_hidden or not func.hidden
            ]
            for i in range(0, len(menu_items)):
                print(" | ".join(menu_items[i : i + 1]))


# 脚本功能封装
class Kylin_Tools_Script:
    @switch_func("0", "退出脚本")
    def exit_script(self):
        print("执行退出脚本")
        exit()

    @switch_func("0.0", "显示菜单")
    def show_menu_srcipt(self):
        print("显示菜单")
        kylin_script_print.show_menu(args.show_hidden)

    @switch_func("1.1", "常用安装(粤政易, WPS, BJCA, 360压缩)")
    # 常用软件按照
    def install_software_common(self):
        self.install_yzy()
        self.install_wps()
        self.install_bjca()
        self.install_360zip()

    @switch_func("1.1.1", "粤政易")
    def install_yzy(self):
        file_urls = {
            "粤政易_3.0.53000": "https://dldir1.qq.com/wework/weworklocalapp/o0CkEv4IalOvf9I2JK-zLHU4kyPVIAWiR1Koscv2has/weworklocal_3.0.53000.75N03.arm64.KylinV10.deb",
        }
        kylin_tools_common.soft_down_file(file_urls, kylin_file_path)

    @switch_func("1.1.2", "WPS")
    def install_wps(self):
        file_urls = {
            "WPS_11.8.2.10458": "https://kylin-install.oss-cn-guangzhou.aliyuncs.com/soft/wps-office_11.8.2.10458.AK.preload.sw.withsn._arm64.deb",
        }
        kylin_tools_common.soft_down_file(file_urls, kylin_file_path)

    @switch_func("1.1.3", "BJCA证书")
    def install_bjca(self):
        file_urls = {
            "BJCA_3.7.1201.1011": "https://kylin-install.oss-cn-guangzhou.aliyuncs.com/soft/certaide-3.7.1201.1011.deb",
        }
        kylin_tools_common.soft_down_file(file_urls, kylin_file_path)

    @switch_func("1.1.4", "360压缩(修复解压乱码)")
    def install_360zip(self):
        file_urls = {
            "360压缩_1.0.0.1012": "https://kylin-install.oss-cn-guangzhou.aliyuncs.com/soft/360zip_1.0.0_arm64.deb",
        }
        kylin_tools_common.soft_down_file(file_urls, kylin_file_path)

    @switch_func("1.1.5", "数科阅读器")
    def install_sk(self):
        file_urls = {
            "数科阅读器_3.0.21.0526-1": "https://kylin-install.oss-cn-guangzhou.aliyuncs.com/soft/suwellreaderpro_3.0.21.0526-1.aarch64.deb",
        }
        kylin_tools_common.soft_down_file(file_urls, kylin_file_path)

    @switch_func("1.1.6", "微信(Win版)")
    def install_wechat(self):
        os.system("sudo apt update && sudo apt install -y kylin-kwre-wechat")

    @switch_func("1.2.1", "安装WPS证书")
    def install_wps_cert(self):
        down_path = "/usr/local/share/ca-certificates/"
        down_url = "https://kylin-install.oss-cn-guangzhou.aliyuncs.com/driver/kingsoft-wps.crt"
        os.system("sudo wget -P {} {} -q --show-progress".format(down_path, down_url))
        os.system("sudo update-ca-certificates")

    @switch_func("1.2.2", "浏览器配置(360书签)")
    def browser_config(self):
        # 指定360浏览器配置目录
        continue_path = "$HOME/.config/browser360/"
        # 指定360书签存放目录
        bookmarks_path = "$HOME/.config/browser360/Default"

        # 状态文件url
        status_url = "https://kylin-install.oss-cn-guangzhou.aliyuncs.com/soft/browser360/Local%20State"
        # 360书签url
        bookmarks_url = "https://kylin-install.oss-cn-guangzhou.aliyuncs.com/soft/browser360/360Bookmarks"

        # 下载状态文件
        os.system("wget -P {} {} -q --show-progress".format(continue_path, status_url))
        # 下载360书签
        os.system("wget -P {} {} -q --show-progress".format(bookmarks_path, bookmarks_url))

    @switch_func("1.3.1", "WPS卸载并清理残存文件")
    def uninstall_wps(self):
        print("正在卸载WPS")
        os.system("sudo apt autoremove -y wps-office")
        # 删除遗留文件
        print("正在删除遗留文件")
        os.system("sudo rm -rf $HOME/.local/share/Kingsoft/")
        os.system("sudo rm -rf $HOME/.local/share/Trash/")
        print("成功卸载WPS并清除遗留文件")

    @switch_func("2.1", "杀粤政易(解决无法正常收发消息)")
    def kill_yzy(self):
        os.system("sudo killall -9 wwlocal")
        # 生成强制退出粤政易脚本到用户桌面
        os.system('echo "sudo killall -9 wwlocal" > $HOME/桌面/强制退出粤政易.sh')
        os.system("chmod +x $HOME/桌面/强制退出粤政易.sh")
        print("已经生成强制退出粤政易脚本到用户家目录")

    @switch_func("2.2", "腾讯会议修复插件(不含本体)")
    def install_tx(self):
        file_urls = {
            "腾讯会议修复插件X11_Wayland_0.0.3": "https://kylin-install.oss-cn-guangzhou.aliyuncs.com/soft/x11-wayland_0.0.3_arm64.deb",
        }
        kylin_tools_common.soft_down_file(file_urls, kylin_file_path)

    @switch_func("3.0", "查看系统信息")
    def show_sys_info(self):
        print(kylin_script_print.script_env)
        # 内核版本
        print(f"内核版本: {kylin_tools_common.cmd('uname -r')}")
        # 查看授权机器码
        print(f'授权机器码: {kylin_tools_common.cmd("sudo kylin_gen_register")}')
        # 查看授权到期时间
        print(f'授权到期时间: {kylin_tools_common.cmd("kylin-verify")}')
        # 序列号
        print(f'序列号: {kylin_tools_common.cmd("sudo kylin_serial")}')
        # 查询系统版本
        print(f"系统版本: {kylin_tools_common.cmd('cat /etc/.kyinfo')}")

    @switch_func("3.1", "常用公文字体安装")
    def install_font(self):
        # 字体文件URL
        font_url = {
            "仿宋_GB2312": "https://kylin-install.oss-cn-guangzhou.aliyuncs.com/fonts/%E4%BB%BF%E5%AE%8B_GB2312.ttf",
            "方正小标宋_GBK": "https://kylin-install.oss-cn-guangzhou.aliyuncs.com/fonts/%E6%96%B9%E6%AD%A3%E5%B0%8F%E6%A0%87%E5%AE%8B_GBK.ttf",
            "方正小标宋简体": "https://kylin-install.oss-cn-guangzhou.aliyuncs.com/fonts/%E6%96%B9%E6%AD%A3%E5%B0%8F%E6%A0%87%E5%AE%8B%E7%AE%80%E4%BD%93.ttf",
            "楷体_GB2312": "https://kylin-install.oss-cn-guangzhou.aliyuncs.com/fonts/%E6%A5%B7%E4%BD%93_GB2312.ttf",
            "黑体": "https://kylin-install.oss-cn-guangzhou.aliyuncs.com/fonts/%E9%BB%91%E4%BD%93.ttf",
            "wingding": "https://kylin-install.oss-cn-guangzhou.aliyuncs.com/fonts/wingding.ttf",
            "wingdings2": "https://kylin-install.oss-cn-guangzhou.aliyuncs.com/fonts/wingdings2.ttf",
        }
        # 定义字体文件安装路径,如果没有则创建
        font_path = "/usr/share/fonts/myfonts"
        if not os.path.exists(font_path):
            os.system("sudo mkdir -p {}".format(font_path))

        # 下载字体文件
        for font_name, font_url in font_url.items():
            print("正在下载并安装字体文件:{}".format(font_name))
            os.system("sudo wget -P {} {} -q --show-progress".format(font_path, font_url))

        # 关闭软件让修改生效
        input("请手动关闭WPS文字(Word)、WPS表格(Excel)、WPS演示(PPT)之后,按回车键继续...")
        os.system("sudo killall -9 wps")
        os.system("sudo killall -9 wpp")
        os.system("sudo killall -9 et")

    @switch_func("3.2", "升级麒麟商店")
    def upgrade_kylin_store(self):
        os.system("sudo apt update && sudo apt install -y kylin-software-center")

    @switch_func("3.3", "系统更新源及更新软件")
    def update_source(self):
        os.system("sudo apt update && sudo apt upgrade -y")

    @switch_func("3.4", "增加虚拟内存")
    def add_swap(self):
        # 输入要设置的虚拟内存大小
        swap_size = input("请输入要设置的虚拟内存大小(单位:GB, 只需要输入数字): ")
        # 创建交换文件目录
        os.system("sudo mkdir -p /swap")
        # 创建虚拟内存文件
        os.system("sudo fallocate -l {}G /swap/swapfile".format(swap_size))
        # 设置权限
        os.system("sudo chmod 600 /swap/swapfile")
        # 格式化为交换文件
        os.system("sudo mkswap /swap/swapfile")
        # 启用交换文件
        os.system("sudo swapon /swap/swapfile")
        # 添加到fstab文件中, 重启后自动挂载
        os.system("echo '/swap/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab")

    @switch_func("4.0", "安装deepin驱动依赖包", hidden=True)
    def install_uos_driver(self):
        file_urls = {
            "deepin-dlf-verify": "https://kylin-install.oss-cn-guangzhou.aliyuncs.com/driver/1-deepin-elf-verify_1.0.18-1_arm64.deb",
        }
        kylin_tools_common.soft_down_file(file_urls, kylin_file_path)

    @switch_func("4.1", "安装打印机驱动(兄弟和华为)", hidden=True)
    def install_driver_brother(self):
        file_urls = {
            "deepin-dlf-verify": "https://kylin-install.oss-cn-guangzhou.aliyuncs.com/driver/1-deepin-elf-verify_1.0.18-1_arm64.deb",
            "Brother-MFC-8535DN": "https://kylin-install.oss-cn-guangzhou.aliyuncs.com/driver/signed_mfc8535dnpdrv-5.0.1-1.arm64.deb",
            "Brother-MFC-8535DN-BS": "https://kylin-install.oss-cn-guangzhou.aliyuncs.com/driver/signed_printer-driver-bisheng-brother-dcp-l5500d-series_2.0.1_all.deb",
            "HUAWEI-CV81Z-LDM": "https://kylin-install.oss-cn-guangzhou.aliyuncs.com/driver/signed_com.huawei.cv81-series_1.0-53_arm64.deb",
        }
        kylin_tools_common.soft_down_file(file_urls, kylin_file_path)

    @switch_func("7.0", "初始化安装（字体和软件、证书、密码策略）-未完", hidden=True)
    def init_install(self):
        pass

    @switch_func("7.1", "Apt软件源设置", hidden=True)
    def set_apt_source(self):
        # 定义软件源
        lists = inspect.cleandoc(
            r"""
            # W515-本文件由源管理器管理, 会定期检测与修复, 请勿修改本文件
            deb https://archive.kylinos.cn/kylin/KYLIN-ALL 10.1-pv main restricted universe multiverse
            deb https://archive2.kylinos.cn/deb/kylin/production/PART-10_1-kirin990/custom/partner/10_1-kirin990 default all
            deb http://update.private.kylinos.cn:8098/deb/kylin/production/990-update/custom/kylin-desktop/990-update default all
            deb http://archive.kylinos.cn/kylin-tmp-upgrade/szszf990 10.1 main
            deb http://10.224.152.109:8098/deb/kylin/production/KY-990-arm64/custom/kylin-desktop/990-arm64 default all
            deb http://10.224.152.109:8098/deb/kylin/production/990-update/custom/kylin-desktop/990-update default all
            
            # L410-本文件由源管理器管理, 会定期检测与修复, 请勿修改本文件
            # deb https://archive.kylinos.cn/kylin/KYLIN-ALL 10.1-pv main restricted universe multiverse
            # deb https://archive2.kylinos.cn/deb/kylin/production/PART-10_1-kirin990/custom/partner/10_1-kirin990 default all
            # deb http://archive.kylinos.cn/kylin-tmp-upgrade/szszf990 10.1 main
        """
        )

        # 备份apt软件源, 如果备份文件存在就跳过
        print("正在备份软件源...")
        if os.path.exists("/etc/apt/sources.list.bak"):
            print("已经备份过, 跳过")
        else:
            os.system("sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak")
            print("备份完成")

        # 追加内容到软件源
        print("正在更新软件源...")
        os.system(f'sudo echo "{lists}" > /etc/apt/sources.list')
        print("更新完成")

        # 升级软件源
        os.system("sudo apt update -y")

    @switch_func("7.2.1", "查看Audit_log", hidden=True)
    def show_audit_log(self):
        audit_log = inspect.cleandoc(
            """
            #!/bin/bash
            mac_addr=$(ifconfig  | grep -o -E '([[:xdigit:]]{1,2}:){5}[[:xdigit:]]{1,2}')
            sn=$(sudo dmidecode -t system  | grep 'Serial Number' |awk  -F ':'  '{print $2}')
            logname='audit'
            cd $HOME/.local/share/Kingsoft/office6/data/backup
            filenum=$(ls |wc -l)
            echo   "WPS处理文件数量: $filenum"
            time=$(cat /var/log/activation.log | awk '/^[0-9]/ {print $1" "$2}' |awk 'NR==1')
            echo  "第一次开机时间：  $time"
            starttime=$(cat  /var/log/activation.log |wc  -l)
            echo  "开机次数：$starttime"
            echo   "MAC地址: $mac_addr"
            echo   "机器SN号: $sn"
            echo  "IP地址: $(ifconfig -a|grep inet|grep -v 127.0.0.1|grep -v inet6|awk '{print $2}'|tr -d 'addr:')"
        """
        )
        os.system(audit_log)

    @switch_func(
        "7.2.2",
        "破解Audit_log(默认WPS{随机1200-3000}, 开机次数{随机至少280})",
        hidden=True,
    )
    def check_audit_log(self):
        # 破解开机次数和第一次开机时间
        # 写入格式: '2022-12-10 18:37:26 activation: Starting....'
        # 设置log文件路径
        date_time_path = "/var/log/activation.log"
        print("正在设置开机log日志: {}".format(date_time_path))
        print("加权写入中...")
        # 加写权限
        os.system("sudo chmod a+w " + date_time_path)
        # 清空内容
        os.system('echo "" > {}'.format(date_time_path))

        # 破解WPS文件数量
        # 设置目标文件路径
        check_wps_path = "$HOME/.local/share/Kingsoft/office6/data/backup/"
        print("正在设置WPS文件数量, 文件路径: {}".format(check_wps_path))
        os.system("mkdir -p {}".format(check_wps_path))
        for i in range(random.randrange(1200, 3000)):
            kylin_tools_common.cmd(
                "dd if=/dev/zero of={}{}.docx bs=1M count=0 seek={}".format(check_wps_path, i, random.randrange(100))
            )
        print("设置成功")

        # 计算设定时间到今日天数
        range_date = (datetime.date.today() - (datetime.datetime.strptime("2021-10-01", "%Y-%m-%d").date())).days
        # 反向循环天数-反向是为了开始时间在前面
        for i in reversed(range(random.randrange(280, range_date))):
            # 操作循环的天数
            date = datetime.date.today() - datetime.timedelta(days=i)
            time = "8:" + str(random.randrange(10, 40)) + ":" + str(random.randrange(1, 60))
            # 判断是否周末
            if date.isoweekday() != 6 and date.isoweekday() != 7:
                # 按照固定格式导进log文件
                date_time = str(date) + " " + time + " activation: Starting...."
                # print(date_time)
                os.system('echo "{}" >> {}'.format(date_time, date_time_path))
        print("写入成功")

    @switch_func("7.3", "设置密码相关策略-未完", hidden=True)
    def set_passwd(self):
        pass

    @switch_func("7.4", "去除开机界面后两项-未完", hidden=True)
    def remove_boot(self):
        pass

    @switch_func("7.5", "设置FTP扫描, 账号为FTP-未完", hidden=True)
    def set_ftp(self):
        pass

    @switch_func("7.6", "UOS进入开发者模式, 开启root权限", hidden=True)
    def set_root(self):
        file_urls = {
            "deepin-dlf-verify": "https://kylin-install.oss-cn-guangzhou.aliyuncs.com/driver/1-deepin-elf-verify_1.0.18-1_arm64.deb",
            "signed_open-root": "https://kylin-install.oss-cn-guangzhou.aliyuncs.com/soft/signed_open-root.deb",
        }
        kylin_tools_common.soft_down_file(file_urls, kylin_file_path)
        print("开启成功, 重启后生效")


# 创建命令行解析器
parser = argparse.ArgumentParser(description="Kylin System Script")
parser.add_argument("-f", "--function", help="指定要执行的功能", choices=list(functions.keys()))
parser.add_argument("-k", "--show-hidden", action="store_true", help="显示隐藏菜单项")

# 解析命令行参数
args = parser.parse_args()

# 实例化共用类
kylin_tools_common = Kylin_Tools_Common()
# 实例化显示菜单类
kylin_script_print = Kylin_Script_Print()
# 实例化脚本类
kylin_tools_script = Kylin_Tools_Script()


def main():
    # 命令行参数执行
    if args.function:
        functions[args.function]()
    else:
        # 显示预设菜单
        kylin_script_print.show_menu(args.show_hidden)
        while True:
            # 获取用户输入
            choice = input("如需执行脚本功能, 请输入菜单选项==>")

            # 根据用户输入执行对应的函数
            if choice in functions:
                # function_to_call = functions[choice]
                # function_to_call(kylin_tools_script)
                # 上面两行的简单写法，因为函数是实例化类后调用的，所以要把类本身传进去
                functions[choice](kylin_tools_script)
            else:
                print("输入错误, 请重新输入！")


if __name__ == "__main__":
    main()
